package cate.common.table;

import easy.java.time.DateTool;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;

import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;

@Slf4j
public class XSSFRowWrap {

    private static final ThreadLocal<String> currentSheetName = new ThreadLocal<>();
    public static void setCurrentSheet(String description) {
        currentSheetName.set(description);
    }

    public XSSFRow row;

    public Map<String, Integer> fieldIndexMap;

    public XSSFRowWrap(XSSFRow row, Map<String, Integer> fieldIndexMap) {
        this.row = row;
        this.fieldIndexMap = fieldIndexMap;
    }

    public XSSFCell getCell(String field) {
        Integer index = this.fieldIndexMap.get(field);
        if(index == null) {
            return null;
        }
        if(this.row == null) {
            return null;
        }
        return this.row.getCell(index);
    }

    public String getString(String field, String defaultValue) {
        XSSFCell cell = getCell(field);
        if(cell == null) {
            return defaultValue;
        }
        try {
            cell.setCellType(CellType.STRING);
        } catch (Exception e) {
            String debugId = "";
            String content = "";
            try {
                debugId = getString("ID");
                content = cell.getStringCellValue();
            } catch (Exception ee) {
                log.warn("获取debugId, content失败", ee);
            }
            log.warn("设置CellType.STRING失败, filed={}, debugId={}, content={}", field, debugId, content);
        }
        try {
            return cell.getStringCellValue();
        } catch (Exception e) {
            return defaultValue;
        }
    }

    public String getString(String field) {
        return getString(field, null);
    }

    public Integer getInteger(String field, Integer defaultValue) {
        return cellInteger(getCell(field), defaultValue, field);
    }

    public Integer getInteger(String field) {
        return cellInteger(getCell(field), null, field);
    }

    public Long getLong(String field, Long defaultValue) {
        return cellLong(getCell(field), defaultValue, field);
    }

    public Long getLong(String field) {
        return cellLong(getCell(field), null, field);
    }

    public Short getShort(String field, Short defaultValue) {
        return cellShort(getCell(field), defaultValue, field);
    }

    public Short getShort(String field) {
        return cellShort(getCell(field), null, field);
    }

    public Byte getByte(String field, Byte defaultValue) {
        return cellByte(getCell(field), defaultValue, field);
    }

    public Byte getByte(String field) {
        return cellByte(getCell(field), null, field);
    }

    public Boolean getBoolean(String field, Boolean defaultValue) {
        return cellBoolean(getCell(field), defaultValue, field);
    }

    public Boolean getBoolean(String field) {
        return cellBoolean(getCell(field), null, field);
    }

    public Float getFloat(String field, Float defaultValue) {
        return cellFloat(getCell(field), defaultValue, field);
    }

    public Float getFloat(String field) {
        return cellFloat(getCell(field), null, field);
    }

    public Double getDouble(String field, Double defaultValue) {
        return cellDouble(getCell(field), defaultValue, field);
    }

    public Double getDouble(String field) {
        return cellDouble(getCell(field), null, field);
    }

    public Date getDate(String field, Date defaultValue) {
        return cellDate(getCell(field), defaultValue, field);
    }

    public Date getDate(String field) {
        return cellDate(getCell(field), null, field);
    }

    public static String cellString(XSSFCell cell, String defaultValue) {
        if(cell == null) {
            return defaultValue;
        }
        try {
            CellType cellType = cell.getCellType();
            if (cellType == CellType.NUMERIC) {
                double numericCellValue = cell.getNumericCellValue();
                if (numericCellValue % 1 == 0) {
                    return String.valueOf((long) numericCellValue);
                }
                return String.valueOf(numericCellValue);
            } else if (cellType == CellType.BOOLEAN) {
                boolean booleanCellValue = cell.getBooleanCellValue();
                return String.valueOf(booleanCellValue);
            } else if (cellType == CellType.STRING) {
                return String.valueOf(cell.getStringCellValue());
            } else if (cellType == CellType.BLANK) {
                return defaultValue;
            } else if (cellType == CellType.ERROR) {
                return defaultValue;
            } else {
                String formulaCellValue = defaultValue;
                try {
                    formulaCellValue = cell.getStringCellValue();
                } catch (Exception e0) {
                    try {
                        double tmpNum = cell.getNumericCellValue();
                        if (tmpNum % 1 == 0) {
                            formulaCellValue = String.valueOf((long) tmpNum);
                        } else {
                            formulaCellValue = String.valueOf(tmpNum);
                        }
                    } catch (Exception e1) {
                        try {
                            formulaCellValue = String.valueOf(cell.getBooleanCellValue());
                        } catch (Exception e2) {
                            try {
                                formulaCellValue = DateTool.instance().format(cell.getDateCellValue());
                            } catch (Exception e3) {
                                //
                            }
                        }
                    }
                }
                return formulaCellValue;
            }
        } catch (Exception e) {
            return cell.getRawValue();
        }
    }

    protected Integer cellInteger(XSSFCell cell, Integer defaultValue, String field) {
        String str = cellString(cell, null);
        if(StringUtils.isBlank(str)) return defaultValue;
        try {
            return new BigDecimal(str).intValue();
        } catch (Exception e) {
            report(this, field, e);
            return defaultValue;
        }
    }

    protected Long cellLong(XSSFCell cell, Long defaultValue, String field) {
        String str = cellString(cell, null);
        if(str == null) return defaultValue;
        try {
            return new BigDecimal(str).longValue();
        } catch (Exception e) {
            report(this, field, e);
            return defaultValue;
        }
    }

    protected Short cellShort(XSSFCell cell, Short defaultValue, String field) {
        String str = cellString(cell, null);
        if(str == null) return defaultValue;
        try {
            return new BigDecimal(str).shortValue();
        } catch (Exception e) {
            report(this, field, e);
            return defaultValue;
        }
    }

    protected Byte cellByte(XSSFCell cell, Byte defaultValue, String field) {
        String str = cellString(cell, null);
        if(str == null) return defaultValue;
        try {
            return new BigDecimal(str).byteValue();
        } catch (Exception e) {
            report(this, field, e);
            return defaultValue;
        }
    }

    protected Boolean cellBoolean(XSSFCell cell, Boolean defaultValue, String field) {
        String str = cellString(cell, null);
        if(StringUtils.isBlank(str)) return defaultValue;
        if("true".equals(str)) return true;
        return str.contains("1");
    }

    protected Float cellFloat(XSSFCell cell, Float defaultValue, String field) {
        String str = cellString(cell, null);
        if(str == null) return defaultValue;
        try {
            return new BigDecimal(str).floatValue();
        } catch (Exception e) {
            report(this, field, e);
            return defaultValue;
        }
    }

    protected Double cellDouble(XSSFCell cell, Double defaultValue, String field) {
        String str = cellString(cell, null);
        if(str == null) return defaultValue;
        try {
            return new BigDecimal(str).doubleValue();
        } catch (Exception e) {
            report(this, field, e);
            return defaultValue;
        }
    }

    protected Date cellDate(XSSFCell cell, Date defaultValue, String field) {
        String str = cellString(cell, null);
        if(str == null) return defaultValue;
        try {
            return DateTool.instance().parseOrNull(str);
        } catch (Exception e) {
            report(this, field, e);
            return defaultValue;
        }
    }

    /** 把值重写回row中去 */
    public void setValue(String field, Object value) {
        XSSFCell cell = this.getCell(field);
        if(cell != null) {
            setCellObject(cell, value);
        } else {
            Integer index = this.fieldIndexMap.get(field);
            if(index != null) {
                cell = this.row.createCell(index);
                setCellObject(cell, value);
            } else {
                System.err.println("field=" + field + "时，cell为null");
            }
        }
    }

    public static void setCellObject(XSSFCell cell, Object value) {
        if(value == null) {
            setCellString(cell, "");
        } else {
            if(value instanceof Integer) {
                setCellDouble(cell, ((Integer) value).doubleValue());
            } else if(value instanceof Double) {
                setCellDouble(cell, value);
            } else if(value instanceof Long) {
                setCellDouble(cell, ((Long) value).doubleValue());
            } else if(value instanceof Float) {
                setCellDouble(cell, ((Float) value).doubleValue());
            } else if(value instanceof Byte) {
                setCellDouble(cell, ((Byte) value).doubleValue());
            } else if(value instanceof Character) {
                setCellDouble(cell, Double.valueOf(""+value));
            } else if (value instanceof BigDecimal) {
                setCellDouble(cell, ((BigDecimal) value).doubleValue());
            } else if(value instanceof Boolean) {
                setCellBoolean(cell, (Boolean) value);
            } else if(value instanceof Date) {
                setCellDate(cell, (Date) value);
            } else if(value instanceof Calendar) {
                setCellCalendar(cell, (Calendar) value);
            } else if(value instanceof String) {
                setCellString(cell, (String)value);
            } else {
                System.err.println("setCellObject 异常 cell=" + cell + ", value=" + value);
            }
        }
    }

    private static void setCellString(XSSFCell cell, String value) {
        cell.setCellValue(value);
    }

    private static void setCellDouble(XSSFCell cell, Object number) {
        double value = number != null ? (double)number : 0;
        cell.setCellValue(value);
    }

    private static void setCellBoolean(XSSFCell cell, Boolean value) {
        double v = 0;
        if(value != null) {
            v = value ? 1 : 0;
        }
        cell.setCellValue(v);
    }

    private static void setCellDate(XSSFCell cell, Date value) {
        cell.setCellValue(value);
    }

    private static void setCellCalendar(XSSFCell cell, Calendar value) {
        cell.setCellValue(value);
    }

    private static void report(XSSFRowWrap xrw, String field, Exception e) {
        StringBuilder sb = new StringBuilder();
        for(String key : xrw.fieldIndexMap.keySet()) {
            int idx = xrw.fieldIndexMap.get(key);
            try {
                sb.append(" ");
                sb.append(key);
                sb.append(":");
                sb.append(xrw.row.getCell(idx).getRawValue());
            } catch (Exception ignored) {

            }
        }
        log.error("{} 配置表中 字段:{} 解析出现异常 {}  已被解析的数据：{} ", XSSFRowWrap.currentSheetName.get(), field, e.getMessage(), sb);
    }
}
